package com.bytedance.improvingroad.widget

import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.View
import android.widget.OverScroller
import com.bytedance.improvingroad.R
import com.bytedance.improvingroad.utils.Utils
import kotlin.properties.Delegates

/**
 * Created by chenxiong
 * date 1/29/22
 */
class DefinePhotoView @JvmOverloads constructor(
    context: Context,
    attr: AttributeSet? = null,
    style: Int = 0
) : View(context, attr, style) {
    private var smallScale = 0f
    private var bigScale = 0f

    private var offsetX = 0f
    private var offsetY = 0f

    private var originalOffsetX by Delegates.notNull<Float>()
    private var originalOffsetY by Delegates.notNull<Float>()

    private var isEnlarge = false

    private lateinit var bitmap: Bitmap
    private val OVER_SCALE_FACTOR = 1.5f

     var currentScale = 0f
         set(value) {
            field = value
            invalidate()
        }

    private val mPaint = Paint(Paint.ANTI_ALIAS_FLAG)

    private var gestureDetector: GestureDetector

    val scaleAnimator: ObjectAnimator by lazy {
        ObjectAnimator.ofFloat(this, "currentScale", smallScale,bigScale)
    }

    private lateinit var overScroller: OverScroller

    private lateinit var scaleGestureDetector: ScaleGestureDetector

    init {
        gestureDetector = GestureDetector(context, PhotoGestureDetector())
        init()
    }

    fun init() {
        val option = BitmapFactory.Options()
        option.inJustDecodeBounds = true
        BitmapFactory.decodeResource(resources, R.drawable.pic1, option)
        option.inJustDecodeBounds = false
        option.inDensity = option.outWidth
        option.inTargetDensity = Utils.dp2px(300)
        bitmap = BitmapFactory.decodeResource(resources, R.drawable.pic1, option)

        overScroller = OverScroller(context)

        scaleGestureDetector = ScaleGestureDetector(context, PhotoScaleGesture())

    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)

        originalOffsetX = (width - bitmap.width) / 2f
        originalOffsetY = (height - bitmap.height) / 2f

        if (bitmap.width / bitmap.height > width / height) {
            smallScale = (width / bitmap.width).toFloat()
            bigScale = height / bitmap.height * OVER_SCALE_FACTOR
        } else {
            smallScale = (height / bitmap.height).toFloat()
            bigScale = width / bitmap.width * OVER_SCALE_FACTOR
        }
        currentScale = smallScale
    }

    override fun onDraw(canvas: Canvas) {
        val scaleFaction = (currentScale - smallScale) / (bigScale - smallScale)

        canvas.translate(offsetX * scaleFaction, offsetY * scaleFaction)

        canvas.scale(currentScale, currentScale, width / 2f, height / 2f)

        canvas.drawBitmap(bitmap, originalOffsetX, originalOffsetY, mPaint)
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        // 响应事件优先考虑双指缩放
        var result = scaleGestureDetector.onTouchEvent(event)
        if (!scaleGestureDetector.isInProgress) {
            result = gestureDetector.onTouchEvent(event)
        }
        return result
    }

    private fun fixOffsets() {
        offsetX = Math.min(offsetX, (bitmap.width * bigScale - width) / 2)
        offsetX = Math.max(offsetX, -(bitmap.width * bigScale - width) / 2)
        offsetY = Math.min(offsetY, (bitmap.height * bigScale - height) / 2)
        offsetY = Math.max(offsetY, -(bitmap.height * bigScale - height) / 2)
    }

    inner class FlingRunnable : Runnable {
        override fun run() {
            if (overScroller.computeScrollOffset()) {
                offsetX = overScroller.currX.toFloat()
                offsetY = overScroller.currY.toFloat()
                invalidate()
                postOnAnimation(this)
            }
        }
    }

    inner class PhotoGestureDetector : GestureDetector.SimpleOnGestureListener() {
        override fun onDown(e: MotionEvent): Boolean {
            return true
        }

        override fun onShowPress(e: MotionEvent) {
            super.onShowPress(e)
        }

        override fun onSingleTapUp(e: MotionEvent): Boolean {
            return super.onSingleTapUp(e)
        }

        override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {
            if(isEnlarge) {
                offsetX -= distanceX
                offsetY -= distanceY
                fixOffsets()
                invalidate()
            }
            return super.onScroll(e1, e2, distanceX, distanceY)
        }

        override fun onLongPress(e: MotionEvent) {
            super.onLongPress(e)
        }

        override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
            // overX overY就是为什么使用overScroller的原因
            if (isEnlarge) {
                overScroller.fling(offsetX.toInt(), offsetY.toInt(), velocityX.toInt(), velocityY.toInt(),
                    -((bitmap.width * bigScale - width) / 2).toInt(), ((bitmap.width * bigScale - width) / 2).toInt(),
                    -((bitmap.height * bigScale - height) / 2).toInt(), ((bitmap.height * bigScale - height) / 2).toInt()
                ,300, 300)
                //下一帧的动画的时候执行
                postOnAnimation(FlingRunnable())

            }
            return super.onFling(e1, e2, velocityX, velocityY)
        }

        override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
            return super.onSingleTapConfirmed(e)
        }

        override fun onDoubleTap(e: MotionEvent): Boolean {
            isEnlarge = !isEnlarge
            if (isEnlarge) {
                offsetX = e.x - width / 2f - (e.x - width / 2f) * bigScale / smallScale
                offsetY = e.y - height / 2f - (e.y - height / 2f) * bigScale / smallScale
                fixOffsets()
                scaleAnimator.start()
            } else {
                scaleAnimator.reverse()
            }
            return super.onDoubleTap(e)
        }

        override fun onDoubleTapEvent(e: MotionEvent): Boolean {
            return super.onDoubleTapEvent(e)
        }

        override fun onContextClick(e: MotionEvent): Boolean {
            return super.onContextClick(e)
        }
    }

    inner class PhotoScaleGesture : ScaleGestureDetector.OnScaleGestureListener {
        private var initScale = 0f
        override fun onScale(detector: ScaleGestureDetector): Boolean {
            if ((currentScale > smallScale && !isEnlarge) || (currentScale == smallScale && !isEnlarge)) {
                isEnlarge = !isEnlarge
            }
            // 缩放因子
            currentScale = initScale * detector.scaleFactor
            invalidate()
            return false
        }
        override fun onScaleBegin(detector: ScaleGestureDetector?): Boolean {
            initScale = currentScale
            return true
        }
        override fun onScaleEnd(detector: ScaleGestureDetector?) { }
    }
}